package main

import (
	"fmt"
	"strings"
)

var num int = 10
var numx2, numx3 int

func main() {
	println("In main before calling greeting")
	greeting()
	println("In main after calling greeting")
	fmt.Printf("MultiPly3Nums 2 * 5 * 6 = %d\n", MultiPly3Nums(2, 5, 6))
	numx2, numx3 = getx2Andx3(num)
	PrintValues()
	var i1 int
	var f1 float32
	i1, _, f1 = ThreeValues()
	fmt.Printf("The int: %d, the float: %f\n", i1, f1)

	var min, max int
	min, max = MinMax(78, 65)
	fmt.Printf("Minmium is: %d, Maximum is: %d\n", min, max)

	n := 0
	reply := &n
	Multiply(10, 5, reply)
	fmt.Printf("Multiply: %d\n", *reply)

	fmt.Printf("The minimux is: %d\n", mi(1, 3, 10, 22, 83))

	function1()

	result := 0
	for i := 0; i < 10; i++ {
		result = fiboinacci(i)
		fmt.Printf("fibonacci(%d) is: %d\n", i, result)
	}

	fmt.Printf("%d is even: is %t\n", 16, even(16))
	fmt.Printf("%d is odd: is %t\n", 17, odd(17))
	n = 9
	result, n = fibonacci1(n)
	fmt.Printf("the %d-th fibonacci number is: %d\n", n, result)

	recurisivePrint(10)
	callback(1, add)
	f()

	p2 := add2()
	fmt.Printf("Call Add2 for 3 gives: %v\n", p2(3))

	twoAdder := add1(2)
	fmt.Printf("The result is: %v\n", twoAdder(3))

	addBmp := makeAddSuffix(".bmp")
	name := addBmp("bmpFile")
	fmt.Printf("File Nmae is: %s\n", name)
}

func makeAddSuffix(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

func add2() func(b int) int {
	return func(b int) int {
		return b + 2
	}
}

func add1(a int) func(b int) int {
	return func(b int) int {
		return a + b
	}
}

func f() {
	for i := 0; i < 4; i++ {
		g := func(i int) { fmt.Printf("%d ", i) }
		g(i)
		fmt.Printf(" - g is of type %T and has value %v\n", g, g)
	}
}

func add(a, b int) {
	fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}

func callback(y int, f func(int, int)) {
	f(y, 2)
}

func recurisivePrint(n int) {
	fmt.Println(n)
	if n < 2 {
		return
	} else {
		recurisivePrint(n - 1)
	}

}

func fibonacci1(n int) (val, pos int) {
	if n <= 1 {
		val = 1
	} else {
		v1, _ := fibonacci1(n - 1)
		v2, _ := fibonacci1(n - 2)
		val = v1 + v2
	}
	pos = n
	return
}

func even(n int) bool {
	if n == 0 {
		return true
	}
	return odd(revsign(n) - 1)
}

func odd(n int) bool {
	if n == 0 {
		return false
	}
	return even(revsign(n) - 1)
}

func revsign(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

func fiboinacci(n int) (res int) {
	if n <= 1 {
		res = 1
	} else {
		res = fiboinacci(n-1) + fiboinacci(n-2)
	}

	return
}

func trace(s string) {
	fmt.Printf("entering: %s\n", s)
}

func untrace(s string) {
	fmt.Printf("Leaving: %s\n", s)
}

func function1() {
	fmt.Printf("In function1 at the top\n")
	defer function2()
	fmt.Printf("In function1 at the bottom!\n")
}

func function2() {
	trace("function2")
	defer untrace("function2")
	fmt.Printf("Function2: Deferred until the end of the calling function!\n")
}

func mi(s ...int) int {
	if len(s) == 0 {
		return 0
	}
	min := s[0]
	for _, v := range s {
		if v < min {
			min = v
		}
	}

	return min
}

func Multiply(a, b int, reply *int) {
	*reply = a * b
}

func greeting() {
	return
	println("In greeting!!!!!!")
}

func MultiPly3Nums(a int, b int, c int) int {
	return a * b * c
}

func PrintValues() {
	fmt.Printf("num = %d, 2x num = %d, 3x num = %d\n", num, numx2, numx3)
}

func getx2Andx3(input int) (x2 int, x3 int) {
	x2 = 2 * input
	x3 = 3 * input
	return
}

func ThreeValues() (int, int, float32) {
	return 5, 6, 7.5
}

func MinMax(a int, b int) (min int, max int) {
	if a < b {
		min = a
		max = b
	} else {
		min = b
		max = a
	}
	return
}
